<?php
/**
 * Created by PhpStorm.
 * User: Administrator
 * Date: 2016/6/13
 * Time: 15:29
 */
class Alipay
{
    private $title;          // 订单名称
    private $orderSn;
    private $accountId;
    private $notifyUrl;
    private $returnUrl;
    private $rsaType;

    /**
     *构造方法
     * @param int $accountId
     * @param string $orderSn
     * @param string $title
     * @param string $notifyUrl
     * @param string $returnUrl
     */
    public function __construct($accountId, $orderSn, $title, $notifyUrl = '', $returnUrl = '')
    {
        $this->accountId = $accountId;
        $this->title = $title;
        $this->orderSn = $orderSn;
//        $this->notifyUrl = $notifyUrl ? $notifyUrl : C('site_url') . U('alipay/alipayNotify/notify');
        $this->notifyUrl = C('weixin') . U('alipay/alipayNotify/notify');
        $this->returnUrl = $returnUrl;
    }

    /**
     *服务窗支付
     */
    public function windowPay()
    {
        $payData = self::getAlipayPayData($this->accountId, $this->orderSn);
        $verifyField = array(
            'partner',                // 合作者支付宝账号ID
            'sellerId',                // 卖家支付宝用户号
            'returnUrl',            // 页面跳转同步通知页面路径
            'orderName',            // 订单名称
            'orderDesc',            // 订单描述
            'orderSn',                // 订单编号
            'orderAmount',            // 订单金额
        );
        foreach ($verifyField as $key => $value) {
            if (empty($payData[$value])) {
                return array('status' => 'F', 'message' => $value . '不能为空');
            }
        }

        //超时时间
        $timeout_express = "15d";
        vendor("Alipay/buildermodel/AlipayTradeWapPayContentBuilder");
        $payRequestBuilder = new AlipayTradeWapPayContentBuilder();
        $payRequestBuilder->setBody($payData['orderDesc']);
        $payRequestBuilder->setSubject($payData['orderName']);
        $payRequestBuilder->setOutTradeNo($payData['orderSn']);
        $payRequestBuilder->setTotalAmount($payData['orderAmount']);
        $payRequestBuilder->setTimeExpress($timeout_express);
        // 查询支付宝配置信息
        $alipayInfo = D('Alipay/Alipay')->getInfo(array('account_id' => $this->accountId));
        //判断是否有服务商
        if($alipayInfo['sys_service_provider_id']){
            $payRequestBuilder->setServiceProviderId($alipayInfo['sys_service_provider_id']);
        }
        $appid = $alipayInfo['appid'];
        $privateKey = $alipayInfo['rsa_private_key'];
        $config = array(
            'gatewayUrl' => 'https://openapi.alipay.com/gateway.do',
            'app_id' => $appid,
            'merchant_private_key' => $privateKey,
            'charset' => 'UTF-8',
        );
        vendor("Alipay/service/AlipayTradeService");
        $payResponse = new AlipayTradeService($config,$alipayInfo['rsa_type']);
        return $result = $payResponse->wapPay($payRequestBuilder, $payData['returnUrl'], $payData['notifyUrl']);
    }

    /**
     *二维码支付
     */
    public function codePay()
    {
        vendor('Alipay.AlipayBarPay');
        // 查询支付宝配置信息
        $alipayInfo = D('Alipay/Alipay')->getInfo(array('account_id' => $this->accountId));

        $appid = $alipayInfo['appid'];
        $privateKey = $alipayInfo['rsa_private_key'];
        $token = $alipayInfo['token'];
        // 获取订单信息
        $orderInfo = $this->getInfoFromOrder($this->orderSn);

        $alipay = new AlipayBarPay($appid, $privateKey, '', $token, $this->notifyUrl,'',$alipayInfo['rsa_type']);

        // 请求支付
        $res = $alipay->qrpay($orderInfo['order_sn'], $orderInfo['goods_amount'], $this->title);

        if ($res->alipay_trade_precreate_response->code == 10000 && $res->alipay_trade_precreate_response->msg == 'Success') {
            return array('status' => 'S', 'out_trade_no' => $res->alipay_trade_precreate_response->out_trade_no, 'qr_code' => $res->alipay_trade_precreate_response->qr_code);
        } else {
            return array('status' => 'F', 'message' => 'msg:' . $res->alipay_trade_precreate_response->msg . ';sub_code:' . $res->alipay_trade_precreate_response->sub_code . ';sub_msg:' . $res->alipay_trade_precreate_response->sub_msg);
        }
    }


    /**
     *web网站支付
     */
    public function webPay()
    {
        vendor('Alipay.AlipayBarPay');
        // 查询支付宝配置信息
        $alipayInfo = D('Alipay/Alipay')->getInfo(array('account_id' => $this->accountId));
        $appid = $alipayInfo['appid'];
        $privateKey = $alipayInfo['rsa_private_key'];
        $token = $alipayInfo['token'];
        $key = $alipayInfo['key'];

        // 获取订单信息
        $orderInfo = $this->getInfoFromOrder($this->orderSn);
        $alipay = new AlipayBarPay($appid, $privateKey, '', $token, $this->notifyUrl, $this->returnUrl);
        $res = $alipay->webPay($key, $orderInfo['order_sn'], $orderInfo['order_amount'], $this->title);
        echo $res;
    }


    /**
     * 获得支付宝支付配置及订单数据
     * @param int $accountId 账号id
     * @param array $orderSn 订单号
     * @return array
     */
    public function getAlipayPayData($accountId, $orderSn)
    {
        $AlipayInfo = D('Alipay/Alipay')->getInfo(array('account_id' => $accountId));
        if (empty($AlipayInfo)) {
            return array();
        }

        // 获取订单信息
        $orderInfo = $this->getInfoFromOrder($orderSn);
        if(!$orderInfo['title']){
            $orderInfo['title'] = $this->title?$this->title:'订单支付';
        }
        $payData = array(
            'partner' => $AlipayInfo['appid'],                // 合作者支付宝账号ID
            'sellerId' => $AlipayInfo['appid'],            // 卖家支付宝用户号
            'returnUrl' => $this->returnUrl,        // 页面跳转同步通知页面路径
            'orderName' => $orderInfo['title'], // 订单名称
            'orderSn' => $orderInfo['order_sn'], // 订单编号
            'orderAmount' => $orderInfo['order_amount'], // 订单金额
            'orderDesc' => $orderInfo['title'], // 订单描述
            'notifyUrl' => $this->notifyUrl,
        );

        return $payData;
    }

    /**
     *从订单从获取订单数据
     */
    public function getInfoFromOrder($orderSn)
    {
        // 解析订单编号内的模块ID
        $moduleId = substr($orderSn, 14, 3);
        $moduleId = preg_replace('/^0+/', '', $moduleId);
        // 获取对应模块信息
        $moduleInfo = D('Base/Module')->getByPk($moduleId);
        // 查询订单信息
        $orderInfo = D('Base/' . $moduleInfo['order_model_name'])->getByOrderSn($orderSn);
        return $orderInfo;
    }

    /*
     * 查询订单接口
	 * 用于交易创建后，查询订单的支付状态
	 * $out_trade_no string  订单的交易号
	 */
    public function orderQuery()
    {
        // 查询支付宝配置信息
        $alipayInfo = D('Alipay/Alipay')->getInfo(array('account_id' => $this->accountId));
        if (!$alipayInfo) {
            return array('status' => 'F', 'message' => '支付宝配置信息不能为空');
        }
        vendor('Alipay.AlipayBarPay');
        $appid = $alipayInfo['appid'];
        $privateKey = $alipayInfo['rsa_private_key'];
        $token = $alipayInfo['token'];
        $alipay = new AlipayBarPay($appid, $privateKey, '', $token, $this->notifyUrl);
        $res = $alipay->orderQuery($this->orderSn);
        wLog(date('Y-m-d H:i:s') . ' queryTradeStatus result: ' . var_export($res,true) . "\r\n", 'alipayPay');
        if($res->code != 10000){
            return array('status' => 'F', 'message' => $res->sub_msg);
        }
        return array('status' => 'S', 'data' => $this->object_to_array($res));
    }

    /*
     * 退款订单接口
	 * 用于交易创建后，查询订单的支付状态
	 * $out_trade_no string  订单的交易号
	 */
    public function orderRefund($trade_no = '',$refund_amount,$out_request_no,$out_trade_no = '')
    {
        // 查询支付宝配置信息
        $alipayInfo = D('Alipay/Alipay')->getInfo(array('account_id' => $this->accountId));
        if (!$alipayInfo) {
            return array('status' => 'F', 'message' => '支付宝配置信息不能为空');
        }
        vendor('Alipay.AlipayBarPay');
        $appid = $alipayInfo['appid'];
        $privateKey = $alipayInfo['rsa_private_key'];
        $token = $alipayInfo['token'];
        $alipay = new AlipayBarPay($appid, $privateKey, '', $token, $this->notifyUrl);
        $res = $alipay->refund($trade_no,$refund_amount,$out_request_no,$out_trade_no);
        wLog(date('Y-m-d H:i:s') . ' orderRefund result: ' . var_export($res,true) . "\r\n", 'alipayPay');
        if($res->code != 10000){
            return array('status' => 'F', 'message' => $res->sub_msg);
        }
        return array('status' => 'S', 'data' => $this->object_to_array($res));
    }

    /**
     * 撤销订单接口
     * 用于交易创建后，用户在一定时间内未进行支付，可调用该接口直接将未付款的交易进行关闭。
     * @return array
     */
    public function orderReverse($is_again = 0)
    {
        // 查询支付宝配置信息
        $alipayInfo = D('Alipay/Alipay')->getInfo(array('account_id' => $this->accountId));
        if (!$alipayInfo) {
            return array('status' => 'F', 'message' => '支付宝配置信息不能为空');
        }
        vendor('Alipay.AlipayBarPay');
        $appId = $alipayInfo['appid'];
        $privateKey = $alipayInfo['rsa_private_key'];
        $token = $alipayInfo['token'];
        $alipay = new AlipayBarPay($appId, $privateKey, '', $token, $this->notifyUrl);
        // 请求支付
        $res = $alipay->cancel($this->orderSn);
        wLog(date('Y-m-d H:i:s').' orderReverse result: ' . var_export($res,true) . "\r\n", 'alipayPay');
        if ($res->code != 10000) {
            return array('status' => 'F', 'message' => $res->sub_msg);
        }
        if ($res->retry_flag == 'N') {
            if ($res->action == 'close') {//未支付成功直接撤销
                return array('status' => 'S', 'message' => '撤销成功', 'out_trade_no' => $res->out_trade_no, 'is_refund' => 'N');
            } elseif ($res->action == 'refund') { //支付成功产生了退款的撤销
                return array('status' => 'S', 'message' => '撤销退款成功', 'out_trade_no' => $res->out_trade_no, 'is_refund' => 'Y');
            } else {
                return array('status' => 'S', 'message' => '撤销成功', 'out_trade_no' => $res->out_trade_no);
            }
        } else {
            if ($is_again == 1) { //是否重复调用撤销
                return array('status' => 'F', 'message' => '撤销失败,需要重新撤销');
            } else {
                sleep(1);
                $this->orderReverse(1);
            }
        }
    }

    /**
     * 关闭订单接口
     * 用于交易创建后，用户在一定时间内未进行支付，可调用该接口直接将未付款的交易进行关闭。
     * @return array
     */
    public function orderClose()
    {
        // 查询支付宝配置信息
        $alipayInfo = D('Alipay/Alipay')->getInfo(array('account_id' => $this->accountId));
        if (!$alipayInfo) {
            return array('status' => 'F', 'message' => '支付宝配置信息不能为空');
        }
        vendor('Alipay.AlipayBarPay');
        $appId = $alipayInfo['appid'];
        $privateKey = $alipayInfo['rsa_private_key'];
        $token = $alipayInfo['token'];
        $alipay = new AlipayBarPay($appId, $privateKey, '', $token, $this->notifyUrl);
        // 请求支付
        $res = $alipay->close($this->orderSn);
        wLog(date('Y-m-d H:i:s').' closeOrder result: ' . var_export($res,true) . "\r\n", 'alipayPay');
        if ($res->code != 10000) {
            return array('status' => 'F', 'message' => $res->sub_msg);
        }
        return array('status' => 'S', 'message' => '订单关闭成功', 'out_trade_no' => $res->out_trade_no);
    }

    /**
     * 对象 转 数组
     *
     * @param object $obj 对象
     * @return array
     */
    public function object_to_array($obj) {
        $obj = (array)$obj;
        foreach ($obj as $k => $v) {
            if (gettype($v) == 'resource') {
                return;
            }
            if (gettype($v) == 'object' || gettype($v) == 'array') {
                $obj[$k] = (array)$this->object_to_array($v);
            }
        }

        return $obj;
    }
}